#include "oled.hpp"
#include <string.h>
#include <basic.hpp>
#include <oledfont.h>
extern I2C_HandleTypeDef hi2c1;

bool oled_tx_complete = true;

void oled::write_byte(uint8_t dat, uint8_t mode)
{
    unsigned char ptr[2];
    if (mode)
    {
        ptr[0] = 0x40;
        ptr[1] = dat;
    }
    else
    {
        ptr[0] = 0x00;
        ptr[1] = dat;
    }

    if (HAL_I2C_Master_Transmit(this->i2c, OLED_ADDR, ptr, 2, I2C_TIMEOUT_MS) != HAL_OK)
    {
        LOGI("OLED", "I2C timeout");
    }
}

void oled::drawPixel(uint8_t x, uint8_t y, uint8_t color)
{
    if (x >= OLED_WIDTH || y >= OLED_HEIGHT)
        return;

    uint8_t page = y / 8;
    uint8_t bit = y % 8;
    uint16_t index = page * OLED_WIDTH + x;

    if (color)
        oled_buffer[index] |= (1 << bit);
    else
        oled_buffer[index] &= ~(1 << bit);

    should_refresh = true;
}
/*
    将byte的0~write_len-1位写入到oled_buffer[page * OLED_WIDTH + x]的start_bit~start_bit+write_len-1位
*/
void oled::setByte(uint8_t x, uint8_t page, uint8_t byte, uint8_t start_bit, uint8_t write_len)
{
    if (x >= OLED_WIDTH || page >= OLED_PAGES)
        return;

    if (start_bit == 0 && write_len == 8)
        oled_buffer[page * OLED_WIDTH + x] = byte;
    else if (start_bit + write_len <= 8)
    {
        uint8_t b = oled_buffer[page * OLED_WIDTH + x];

        uint8_t mask = ((1 << write_len) - 1) << start_bit;
        b = (b & (~mask)) | ((byte << start_bit) & mask);

        oled_buffer[page * OLED_WIDTH + x] = b;
    }
}
void oled::drawBitmap(uint8_t sx, uint8_t sy, uint8_t w, uint8_t h, const uint8_t *bitmap, const size_t bitmap_size, uint8_t color)
{
    if (sx >= OLED_WIDTH || sy >= OLED_HEIGHT || w >= OLED_WIDTH || h >= OLED_HEIGHT || w == 0 || h == 0)
        return;

    uint8_t page = sy / 8;
}

void oled::fillRectangle(uint8_t sx, uint8_t sy, uint8_t w, uint8_t h, uint8_t color)
{
    if (sx >= OLED_WIDTH || sy >= OLED_HEIGHT || w >= OLED_WIDTH || h >= OLED_HEIGHT || w == 0 || h == 0)
        return;

    uint8_t start_page = sy / 8, end_page = (sy + h - 1) / 8;
    uint8_t start_bit = sy % 8;

    for (uint8_t page = start_page; page <= end_page && page < OLED_PAGES; page++)
    {
        uint8_t mask = 0xFF; // 默认全字节

        // 计算当前页的掩码
        if (page == start_page && page == end_page)
        {
            // 单页情况
            mask = ((1 << h) - 1) << start_bit; // 天呐 这个操作太聪明了，直接将起始位到结束位的掩码计算出来了 比如0b00100 -1 = 0b00011将后两位直接变成1
        }
        else if (page == start_page)
        {
            // 起始页：从start_bit到字节末尾
            mask = (0xFF << start_bit);
        }
        else if (page == end_page)
        {
            // 结束页：从字节开始到剩余高度
            uint8_t remaining_bits = (sy + h) % 8;

            if (remaining_bits > 0)
                mask = (1 << remaining_bits) - 1;
            else
                mask = 0xFF;
        }
        // 中间页保持0xFF

        // 绘制该页的所有列
        for (uint8_t x = sx; x < sx + w && x < OLED_WIDTH; x++)
        {
            uint16_t byte_idx = page * OLED_WIDTH + x;

            if (color)
                oled_buffer[byte_idx] |= mask;
            else
                oled_buffer[byte_idx] &= ~mask;
        }
    }

    should_refresh = true;
}
void oled::fullscreen(uint8_t color)
{
    if (color)
        memset(oled_buffer, 0xff, sizeof(oled_buffer));
    else
        memset(oled_buffer, 0x00, sizeof(oled_buffer));
}
void oled::clear(void)
{
    memset(oled_buffer, 0x00, sizeof(oled_buffer));
}
void oled::refresh(void)
{
    if (!oled_tx_complete || !should_refresh)
        return;
    oled_tx_complete = false;
    should_refresh = false;

    // 1. 设置起始列和页（通常从 0,0 开始）
    write_byte(0x20, 0); // 设置内存寻址模式
    write_byte(0x00, 0); // 水平寻址模式（推荐）

    write_byte(0x21, 0); // 设置列地址
    write_byte(0, 0);    // 起始列 0
    write_byte(127, 0);  // 结束列 127

    write_byte(0x22, 0); // 设置页地址
    write_byte(0, 0);    // 起始页 0
    write_byte(7, 0);    // 结束页 7

    dma_buffer[0] = 0x40; // 控制字 0x40 表示连续数据
    memcpy(dma_buffer + 1, oled_buffer, sizeof(oled_buffer));

    if (HAL_I2C_Master_Transmit_DMA(this->i2c, OLED_ADDR, dma_buffer, sizeof(dma_buffer)) != HAL_OK)
    {
        LOGI("OLED", "I2C timeout");
    }
    return;

    // // 2. 连续写入 1024 字节数据（整个帧缓冲区）
    // // 注意：I2C 一次不能发太多，需分包（通常 ≤ 32 字节）
    // #define I2C_MAX_BURST 256
    //     uint8_t tx_buf[I2C_MAX_BURST + 1]; // 第1字节是控制字 0x40
    //     tx_buf[0] = 0x40;                  // Co=0, D/C=1 → 连续数据

    //     for (int i = 0; i < (int)sizeof(oled_buffer); i += (I2C_MAX_BURST - 1))
    //     {
    //         int len = _min(I2C_MAX_BURST - 1, sizeof(oled_buffer) - i);
    //         memcpy(&tx_buf[1], &oled_buffer[i], len);
    //         if (HAL_I2C_Master_Transmit(this->i2c, OLED_ADDR, tx_buf, len + 1, I2C_TIMEOUT_MS) != HAL_OK)
    //         {
    //             LOGI("OLED", "Refresh I2C error");
    //             return;
    //         }
    //     }
}

void oled::init(void)
{
    write_byte(0xAE, OLED_CMD); //--turn off oled panel
    write_byte(0x00, OLED_CMD); //---set low column address
    write_byte(0x10, OLED_CMD); //---set high column address
    write_byte(0x40, OLED_CMD); //--set start line address  Set Mapping RAM
                                // Display Start Line (0x00~0x3F)
    write_byte(0x81, OLED_CMD); //--set contrast control register
    write_byte(0xCF, OLED_CMD); // Set SEG Output Current Brightness
    write_byte(0xA1,
               OLED_CMD); //--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    write_byte(0xC8,
               OLED_CMD);       // Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    write_byte(0xA6, OLED_CMD); //--set normal display
    write_byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
    write_byte(0x3f, OLED_CMD); //--1/64 duty
    write_byte(
        0xD3,
        OLED_CMD);              //-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
    write_byte(0x00, OLED_CMD); //-not offset
    write_byte(
        0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
    write_byte(0x80,
               OLED_CMD);       //--set divide ratio, Set Clock as 100 Frames/Sec
    write_byte(0xD9, OLED_CMD); //--set pre-charge period
    write_byte(0xF1,
               OLED_CMD);       // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    write_byte(0xDA, OLED_CMD); //--set com pins hardware configuration
    write_byte(0x12, OLED_CMD);
    write_byte(0xDB, OLED_CMD); //--set vcomh
    write_byte(0x40, OLED_CMD); // Set VCOM Deselect Level
    write_byte(0x20, OLED_CMD); //-Set Page Addressing Mode (0x00/0x01/0x02)
    write_byte(0x02, OLED_CMD); //
    write_byte(0x8D, OLED_CMD); //--set Charge Pump enable/disable
    write_byte(0x14, OLED_CMD); //--set(0x10) disable
    write_byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)
    write_byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)
    write_byte(0xAF, OLED_CMD); /*display ON*/

    clear();
    refresh();
}
oled &oled::instance()
{
    static oled instance(&hi2c1);
    return instance;
}

void oled_test_software()
{
    oled &screen = oled::instance();
    screen.init();

    for (;;)
    {
        screen.drawBitmap(10, 10, 8, 16, asc2_1608['A' - ' '], sizeof(asc2_1608['A' - ' ']), 0);
        screen.refresh();

        continue;
        __PERIOD(OLED_REFLASH, 20,
                 {
                     screen.clear();

                     static int y = 0;
                     if (y <= 0)
                         y = OLED_HEIGHT;
                     screen.fillRectangle(20, y, 60, 15);
                     screen.fillRectangle(22, y + 2, 56, 11, 0);

                     y--;
                     screen.refresh();

                     selfHandler::cout << "ms = " << __GET_PERIOD_DELTA_MS(OLED_REFLASH) << selfHandler::endl;
                 });
    }
}

/////////////////////////Interrupt Handler/////////////////////
/////////////////////////Interrupt Handler/////////////////////
/////////////////////////Interrupt Handler/////////////////////

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if (hi2c == &hi2c1 || 1)
    {
        // OLED 数据发送完成！
        // 可以在这里触发下一次刷新或置标志位
        // serial_send("0\n");
        oled_tx_complete = true;
    }
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
    // 常见错误：NACK、总线错误、仲裁丢失
    if (hi2c->Instance == I2C1)
    {
        oled::instance().init();
        selfHandler::cout << "I2C Error: " << hi2c->ErrorCode << selfHandler::endl;
        // 可尝试复位 I2C：HAL_I2C_DeInit() + MX_I2C1_Init();
    }
}
